#include "stdafx.h"
#include "FileIO.h"
#include "ExchangeData.h"

static gpgme_error_t GetFileSizeFromName(
	const char* file_name,
	DWORD* nLow);

static ssize_t
stream_read (void* h, void *buffer, size_t size)
{
	FILE_IO_META* handle = (FILE_IO_META*)h;
	ssize_t amt = 0;

	amt = (ssize_t)fread (buffer, 1, size, handle->fp);

	if (amt > 0) {
		handle->nCurrPos += amt;
		return amt;
	} else {
		return ferror (handle->fp) ? -1 : 0;
	}
}

static ssize_t
stream_write (void* h, const void *buffer, size_t size)
{
	FILE_IO_META* handle = (FILE_IO_META*)h;
	ssize_t amt = 0;

	amt = (ssize_t)fwrite (buffer, 1, size, handle->fp);

	if (amt > 0) {
		handle->nCurrPos += amt;
		return amt;
	} else {
		return ferror (handle->fp) ? -1 : 0;
	}
}

static off_t
stream_seek (void* h, off_t offset, int whence)
{
	int err;
	ssize_t amt = 0;
	FILE_IO_META* handle = (FILE_IO_META*)h;

	err = fseek (handle->fp, offset, whence);

	if (err) {
		return -1;
	} else {
		amt = (ssize_t)ftell (handle->fp);
		handle->nCurrPos = amt;
		return amt;
	}
}

static void
stream_release (void* h)
{
	FILE_IO_META* handle = (FILE_IO_META*)h;

	//Close file
	fflush (handle->fp);
	fclose(handle->fp);

	//Clean meta
	free(handle);
}

static struct gpgme_data_cbs file_cbs =
{
	stream_read,
	stream_write,
	stream_seek,
	stream_release
};

gpgme_error_t gpgme_data_new_for_read (
	gpgme_data_t *dh,
	const char* file_name,
	FILE_IO_META** fio_handle)
{
	FILE_IO_META* handle = new FILE_IO_META;

	if (GetFileSizeFromName(file_name, &(handle->nLowSize)) != 
		GPG_ERR_NO_ERROR)
	{
		delete handle;
		return GPG_ERR_GENERAL;
	}
	else
	{
		handle->nCurrPos = 0;
	}

	//Must open with "wb+"! 
	//"+" means read write mode!
	fopen_s(
		&(handle->fp),
		file_name,
		"rb");
	if (handle->fp == NULL){
		delete handle;
		return GPG_ERR_GENERAL;
	}
	else
	{
		*fio_handle = handle;
		return gpgme_data_new_from_cbs(dh, &file_cbs, handle);
	}
}

gpgme_error_t gpgme_data_new_for_write (
	gpgme_data_t *dh,
	const char* file_name,
	FILE_IO_META** fio_handle)
{
	FILE_IO_META* handle = new FILE_IO_META;

	handle->nCurrPos = 0;
	handle->nLowSize = 0;

	//Must open with "wb+"! 
	//"+" means read write mode!
	fopen_s(
		&(handle->fp),
		file_name,
		"wb+");
	if (handle->fp == NULL){
		delete handle;
		return GPG_ERR_GENERAL;
	}
	else
	{
		*fio_handle = handle;
		return gpgme_data_new_from_cbs(dh, &file_cbs, handle);
	}
}

gpgme_error_t GetFileSizeFromName(
	const char* file_name,
	DWORD* nLow)
{
	DWORD nHigh = 0;

	HANDLE hFile = CreateFile(
		file_name,
		GENERIC_READ,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		CString stringTmp;
		stringTmp.Format("Can't open file \"%s\"!", file_name);
		AfxMessageBox(stringTmp);
		return GPG_ERR_GENERAL;
	}
	else
	{
		*nLow = GetFileSize(hFile, &nHigh);
		CloseHandle(hFile);
		hFile = INVALID_HANDLE_VALUE;

		if (nHigh > 0)
		{
			AfxMessageBox("File is too big!");	
			return GPG_ERR_GENERAL;
		}
		else
		{
			return GPG_ERR_NO_ERROR;
		}
	}
}